#include "datacenter.h"

namespace model {

DataCenter* DataCenter::instance = nullptr;

DataCenter *DataCenter::getInstance()
{
    if(instance == nullptr) {
        instance = new DataCenter();
    }
    return instance;
}

DataCenter::~DataCenter()
{
    delete myself;
    delete friendList;
    delete chatSessionList;
    delete memberHash;
    delete applyList;
    delete recentMsgHash;
    delete unreadMsgHash;
    delete searchResultList;
    delete historyMsgList;
}

DataCenter::DataCenter()
    :netClient(this)
{
    memberHash = new QHash<QString, QList<UserInfo>>();
    recentMsgHash = new QHash<QString, QList<Message>>();
    unreadMsgHash = new QHash<QString, int>();
}

void DataCenter::initDataFile()
{
    QString basePath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
    QString filePath = basePath + "/ChatClient.json";

    QDir dir;
    if(!dir.exists(basePath)) {
        dir.mkpath(basePath);
    }

    QFile file(filePath);
    bool ok = file.open(QFile::WriteOnly);
    if(!ok) {
        LOG() << "打开文件失败," << file.errorString();
        return;
    }

    QString data = "{\n\n}";
    file.write(data.toUtf8());
}

void DataCenter::saveDataFile()
{
    // 保存 loginSessionId 和 unreadMsgHash 即可,其他数据从服务器加载
    QString filePath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/ChatClient.json";
    QFile file(filePath);
    bool ok = file.open(QFile::WriteOnly);
    if(!ok) {
        LOG() << "打开文件失败," << file.errorString();
        return;
    }

    QJsonObject obj;
    obj["loginSessionId"] = this->loginSessionId;

    QJsonObject unreadObj;
    for(auto it = unreadMsgHash->begin(); it != unreadMsgHash->end(); it ++) {
        unreadObj[it.key()] = it.value();
    }
    obj["unread"] = unreadObj;

    QJsonDocument jsonDoc(obj);
    QString s = jsonDoc.toJson();

    file.write(s.toUtf8());
}

void DataCenter::loadDataFile()
{
    QString filePath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/ChatClient.json";

    // 如果数据文件不存在,则创建空白的数据文件
    QFileInfo fileInfo(filePath);
    if(!fileInfo.exists()) {
        this->initDataFile();
    }

    QFile file(filePath);
    bool ok = file.open(QFile::ReadOnly);
    if(!ok) {
        LOG() << "打开文件失败," << file.errorString();
        return;
    }

    QJsonDocument jsonDoc = QJsonDocument::fromJson(file.readAll());
    if(jsonDoc.isNull()) {
        LOG() << "字符串解析失败, json字符串格式有误";
        return;
    }
    QJsonObject obj = jsonDoc.object();
    this->loginSessionId = obj["loginSessionId"].toString();

    QJsonObject unreadObj = jsonDoc["unread"].toObject();
    this->unreadMsgHash->clear();
    for(auto it = unreadObj.begin();it != unreadObj.end();it ++){
        unreadMsgHash->insert(it.key(), it.value().toInt());
    }
}

QString DataCenter::getLoginSessionId()
{
    return loginSessionId;
}

void DataCenter::ping()
{
    netClient.ping();
}

void DataCenter::getMyselfAsync()
{
    netClient.getMyself(loginSessionId);
}

void DataCenter::resetMyself(std::shared_ptr<bite_im::GetUserInfoRsp> rsp)
{
    if(myself == nullptr) {
        myself = new UserInfo();
    }
    myself->load(rsp->userInfo());
}

UserInfo *DataCenter::getMyself()
{
    return myself;
}

void DataCenter::getFriendListAsync()
{
    netClient.getFriendList(loginSessionId);
}

void DataCenter::resetFriendList(std::shared_ptr<bite_im::GetFriendListRsp> rsp)
{
    if(friendList == nullptr) {
        friendList = new QList<UserInfo>();
    }
    friendList->clear();
    for(auto &e : rsp->friendList()) {
        UserInfo userInfo;
        userInfo.load(e);
        friendList->push_back(userInfo);
    }
}

QList<UserInfo> *DataCenter::getFriendList()
{
    return friendList;
}

void DataCenter::getChatSessionListAsync()
{
    netClient.getChatSessionList(loginSessionId);
}

void DataCenter::resetChatSessionList(std::shared_ptr<bite_im::GetChatSessionListRsp> rsp)
{
    if(chatSessionList == nullptr) {
        chatSessionList = new QList<ChatSessionInfo>();
    }
    chatSessionList->clear();

    for(auto &e : rsp->chatSessionInfoList()) {
        ChatSessionInfo info;
        info.load(e);
        chatSessionList->push_back(info);
    }
}

QList<ChatSessionInfo> *DataCenter::getChatSessionList()
{
    return chatSessionList;
}

void DataCenter::getApplyListAsync()
{
    netClient.getApplyList(loginSessionId);
}

void DataCenter::resetApplyList(std::shared_ptr<bite_im::GetPendingFriendEventListRsp> rsp)
{
    if(applyList == nullptr) {
        applyList = new QList<UserInfo>();
    }
    applyList->clear();

    QList<bite_im::FriendEvent> list = rsp->event();
    for(auto &e : list) {
        UserInfo info;
        info.load(e.sender());
        applyList->push_back(info);
    }
}

QList<UserInfo> *DataCenter::getApplyList()
{
    return applyList;
}

void DataCenter::getRecentMessageListAsync(const QString& chatSessionId, bool updateUI)
{
    netClient.getRecentMessageList(this->loginSessionId, chatSessionId, updateUI);
}

void DataCenter::resetRecentMessageList(std::shared_ptr<bite_im::GetRecentMsgRsp> rsp, const QString& chatSessionId)
{
    QList<Message>& list = (*recentMsgHash)[chatSessionId];
    list.clear();

    for(auto &e : rsp->msgList()) {
        model::Message msg;
        msg.load(e);
        list.push_back(msg);
    }
}

QList<Message> *DataCenter::getRecentMessageList(const QString &chatSessionId)
{
    if(!recentMsgHash->contains(chatSessionId)) return nullptr;
    return &(*recentMsgHash)[chatSessionId];
}

void DataCenter::sendTextMessageAsync(const QString &chatSessionId, const QString &text)
{
    netClient.sendMessage(this->loginSessionId, chatSessionId, model::TEXT_TYPE, text.toUtf8(), "");
}

void DataCenter::modifyNickNameAsync(const QString &newName)
{
    netClient.modifyNickname(this->loginSessionId, newName);
}

void DataCenter::resetNickname(const QString &newName)
{
    if(myself == nullptr) {
        return;
    }
    myself->nickname = newName;
}

void DataCenter::modifyDescriptionAsync(const QString &newDesc)
{
    netClient.modifyDescription(this->loginSessionId, newDesc);
}

void DataCenter::resetDescription(const QString &newDesc)
{
    if(myself == nullptr) {
        return;
    }
    myself->description = newDesc;
}

void DataCenter::getVerifyCodeAsync(const QString &newPhone)
{
    netClient.getVerifyCode(newPhone);
}

void DataCenter::setCurrentSessionId(const QString &chatSessionId)
{
    curSessionId = chatSessionId;
}

QString DataCenter::getCurrentSessionId()
{
    return curSessionId;
}

ChatSessionInfo *DataCenter::findChatSessionInfoById(const QString &chatSessionId)
{
    if(chatSessionList == nullptr) {
        return nullptr;
    }
    for(auto &e : *chatSessionList) {
        if(e.sessionId == chatSessionId) {
            return &e;
        }
    }
    return nullptr;
}

ChatSessionInfo *DataCenter::findChatSessionInfoByUserId(const QString &userId)
{
    if(chatSessionList == nullptr) {
        return nullptr;
    }
    for(auto &e : *chatSessionList) {
        if(e.userId == userId) {
            return &e;
        }
    }
    return nullptr;
}

UserInfo *DataCenter::findUserInfoById(const QString &userId)
{
    if(friendList == nullptr) {
        return nullptr;
    }
    for(auto &e : *friendList) {
        if(e.userId == userId) {
            return &e;
        }
    }
    return nullptr;
}

void DataCenter::topChatSesssionInfo(const ChatSessionInfo &chatSessionInfo)
{
    auto it = chatSessionList->begin();
    for(;it != chatSessionList->end();it ++) {
        if(it->sessionId == chatSessionInfo.sessionId) {
            break;
        }
    }
    if(it == chatSessionList->end()) {
        return;
    }

    ChatSessionInfo info = chatSessionInfo;
    chatSessionList->erase(it);

    chatSessionList->push_front(info);
}

UserInfo DataCenter::removeFromApplyList(const QString &userId)
{
    if(applyList == nullptr) {
        return UserInfo();
    }

    for(auto it = applyList->begin();it != applyList->end();it ++) {
        if(userId == it->userId) {
            UserInfo toDelete = *it;
            applyList->erase(it);
            return toDelete;
        }
    }
    return UserInfo();
}

void DataCenter::addMessage(const Message& msg)
{
    QList<Message>& list = (*recentMsgHash)[curSessionId];
    list.push_back(msg);
}

void DataCenter::clearUnreadMsgCount(const QString &chatSessionId)
{
    (*unreadMsgHash)[chatSessionId] = 0;
    this->saveDataFile();
}

void DataCenter::addUnreadMsgCount(const QString &chatSessionId)
{
    (*unreadMsgHash)[chatSessionId] ++;
    this->saveDataFile();
}

int DataCenter::getUnreadMsgCount(const QString &chatSessionId)
{
    return (*unreadMsgHash)[chatSessionId];
}

const QString& DataCenter::getVerifyCodeId()
{
    return verifyCodeId;
}

void DataCenter::modifyPhoneAsync(const QString &newPhone, const QString &verifyCodeId, const QString &verifyCode)
{
    netClient.modifyPhone(loginSessionId, newPhone, verifyCodeId, verifyCode);
}

void DataCenter::resetPhone(const QString &newPhone)
{
    if(myself == nullptr) {
        return;
    }
    myself->phone = newPhone;
}

void DataCenter::modifyAvatarAsync(const QByteArray &image)
{
    netClient.modifyAvatar(loginSessionId, image);
}

void DataCenter::resetAvatar(const QByteArray &image)
{
    if(myself == nullptr) {
        return;
    }
    myself->avatar = makeIcon(image);
}

void DataCenter::deleteFriendAsync(const QString &userId)
{
    netClient.deleteFriend(loginSessionId, userId);
}

void DataCenter::deleteFriend(const QString &userId)
{
    if(friendList == nullptr || chatSessionList == nullptr) {
        return;
    }

    friendList->removeIf([=](const UserInfo& e){
        return e.userId == userId;
    });
    chatSessionList->removeIf([=](const ChatSessionInfo& e){
        if(e.userId == "") {
            return false;
        }

        if(e.userId == userId) {
            if(e.sessionId == curSessionId) {
                emit clearCurrentChatSession();
            }
            return true;
        }
        return false;
    });
}

void DataCenter::sendFriendApplyAsync(const QString &userId)
{
    netClient.sendFriendApply(loginSessionId, userId);
}

void DataCenter::addFriendApply(const UserInfo &userInfo)
{
    if(applyList == nullptr) {
        return;
    }
    applyList->push_front(userInfo);
}

void DataCenter::acceptFriendApplyAsync(const QString &userId)
{
    netClient.acceptFriendApply(loginSessionId, userId);
}

void DataCenter::rejectFriendApplyAsync(const QString &userId)
{
    netClient.rejectFriendApply(loginSessionId, userId);
}

void DataCenter::createGroupChatSessionAsync(const QList<QString> &userIdList)
{
    netClient.createGroupChatSession(loginSessionId, userIdList);
}

void DataCenter::resetVerifyCodeId(const QString &vcId)
{
    verifyCodeId = vcId;
}

} // end namespace

